package org.jsbd.boss.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.OverridingMethodsMustInvokeSuper;
import javax.annotation.Resource;

import org.jsbd.boss.common.ConstantsCmp;
import org.jsbd.boss.common.redis.RedisClient;
import org.jsbd.boss.dao.*;
import org.jsbd.boss.domian.ChannelApkInfo;
import org.jsbd.boss.domian.ChannelProvinceInfo;
import org.jsbd.boss.domian.InterceptInfo;
import org.jsbd.boss.domian.ProvinceInfo;
import org.jsbd.boss.domian.channel.ChannelApkConfig;
import org.jsbd.boss.domian.channel.ChannelRetentConfig;
import org.jsbd.boss.domian.channel.RetentTimesConfig;
import org.jsbd.boss.domian.weibo.WeiboBrushConfig;
import org.jsbd.boss.domian.weibo.WeiboRetentConfig;
import org.jsbd.boss.service.IChannelApkInfoService;
import org.jsbd.boss.service.IRetentTimesService;
import org.jsbd.boss.util.CacheKey;
import org.jsbd.boss.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jodd.util.StringUtil;

/**
 * 渠道任务配置
 *
 * @author <a href="mailto:zhangbinghua@zhexinit.com" >zbh</a>
 * @version 1.0.0
 */
@Service
public class ChannelConfigService {
    public static final Logger LOGGER = LoggerFactory.getLogger(ChannelConfigService.class);

    @Autowired
    private IChannelApkInfoDAO channelApkInfoDAO;

    @Autowired
    private IChannelProvicneInfoDAO channelProvicneInfoDAO;

    @Autowired
    private IChannelRetentConfigDAO channelRetentConfigDAO;

    @Autowired
    private IIpDAO ipDAO;

    @Autowired
    private IInterceptInfoDAO interceptInfoDAO;

    @Autowired
    private IChannelApkLimitDAO channelApkLimitDAO;

    @Resource
    private RedisClient redisClient;
    
    /**
     * add by zhouc,用于统计
     */
    @Resource
    private RedisClient<String,Object> redisClientMigu;

    @Resource
    private IWeiboRetentConfigDAO weiboRetentConfigDAO;

    @Resource
    private IWeiboBrushConfigDAO weiboBrushConfigDAO;

    @Resource
    private IRetentTimesService retentTimesService;

    @Resource
    private IChannelApkInfoService channelApkInfoService;

    @Resource
    private IChannelApkConfigDAO channelApkConfigDAO;

    @Resource
    private IRetentTimesDao retentTimesDao;

    public Map<String, Object> getAllChannelInfo(ChannelApkInfo channelApkInfo) {

        return channelApkInfoDAO.selectConfigPageListMap(channelApkInfo);

    }

    public void saveChannelInfo(ChannelApkInfo channelApkInfo) {
        channelApkInfoDAO.insertConfig(channelApkInfo);
        if (channelApkInfo.getIsnewUserlimit()) {
            channelApkLimitDAO.deleteChannelApkConfigTimeModel(channelApkInfo.getMark(), ConstantsCmp.add);
        }
    }

    public List<ProvinceInfo> getProvinceInfoList() {
        return ipDAO.getAllprovinceInfo();
    }

    public ChannelApkInfo getProvinceByMark(String mark) {
        return channelApkInfoDAO.getConfigByMark(mark);
    }

    public ChannelApkInfo getProvinceByMarkForPage(String mark) {
        return channelApkInfoDAO.getConfigByMarkForPage(mark);
    }

    public List<InterceptInfo> getInterceptInfoByChannelApkInfo(ChannelApkConfig apkConfig) {
        if (StringUtil.isBlank(apkConfig.getInterceptId())) {
            return null;
        }
        List<InterceptInfo> result = new ArrayList<InterceptInfo>();
        String[] interceptIds = apkConfig.getInterceptId().split(",");
        if (interceptIds != null && interceptIds.length > 0) {
            for (String id : interceptIds) {
                InterceptInfo interceptinfo = interceptInfoDAO.findInterceptInfoByid(id);
                result.add(interceptinfo);
            }
        }
        return result;
    }

    public int updateProvinceByMark(String mark, String openProvince) {
        String[] provinces = openProvince.split(",");
        if (provinces != null && provinces.length > 0) {
            channelProvicneInfoDAO.deleteConfig(mark);
            for (String provicne : provinces) {
                ChannelProvinceInfo t = new ChannelProvinceInfo();
                t.setMark(mark);
                t.setProvinceid(provicne);
                channelProvicneInfoDAO.insertConfig(t);
            }
            return channelApkInfoDAO.updateProvinceByMark(mark, openProvince);
        }
        return 0;

    }

    public int deleteByMark(String mark) {
        return channelApkInfoDAO.deleteConfig(mark);
    }

    public Map<String, Object> selectConfigPageListMap(ChannelProvinceInfo form) {
        return channelProvicneInfoDAO.selectConfigPageListMap(form);
    }

    public int updateProvinceRate(ChannelProvinceInfo form) {
        return channelProvicneInfoDAO.updateProvinceByMark(form);
    }

    public int deleteProvinceBymarkAndid(String mark, String provinceid) {
        return channelProvicneInfoDAO.deleteProvinceByMarkAndId(mark, provinceid);
    }

    public List<ChannelRetentConfig> getRetentBymark(String mark) {
        return channelRetentConfigDAO.getConfigByMark(mark);
    }

    public List<ChannelRetentConfig> getRetentBymarkforPage(String mark) {
        List<ChannelRetentConfig> list = channelRetentConfigDAO.getConfigByMarkForPage(mark);
        if (list != null && list.size() > 0) {
            String key = CacheKey.AR_TASK2 + DateUtil.getDaysOfTime() + mark;
            for (ChannelRetentConfig retentConfig : list) {
                Integer retentDay = retentConfig.getRetentDay();
                String day = DateUtil.getPreSomeDay(retentDay);
                String total = redisClient.evalHget(key, day + "total");
                String execTotal = redisClient.evalHget(key, day + "exectotal");
                if (StringUtil.isNotBlank(total)) {
                    retentConfig.setTotal(Integer.parseInt(total));
                }
                if (StringUtil.isNotBlank(execTotal)) {
                    retentConfig.setExecTotal(Integer.parseInt(execTotal));
                }
            }
        }

        return list;
    }

    public int deleteChannelRetentConfig(ChannelRetentConfig form) {
        String key = CacheKey.AR_TASK2 + DateUtil.getDaysOfTime() + form.getMark();
        String execTotal = redisClient.evalHget(key, DateUtil.getPreSomeDay(form.getRetentDay()) + "exectotal");
        if (StringUtil.isNotBlank(execTotal)) {
            // 增加或者减少
            redisClient.evalHincrby(key, "exectotal", -Integer.parseInt(execTotal));
        }
        deleteWeiboRetentConfig(form);
        
        redisClientMigu.removeHash(CacheKey.LOG_RETENT_CONFIG_MAP_KEY+form.getMark(), String.valueOf(form.getRetentDay()));
        return channelRetentConfigDAO.deleteChannelRetentConfig(form);
    }

    private Set<Integer> initDaySet(List<ChannelRetentConfig> list) {
        Set<Integer> set = new HashSet<Integer>();
        if (list != null && list.size() > 0) {
            for (ChannelRetentConfig config : list) {
                set.add(config.getRetentDay());
            }
        }
        return set;
    }

    @Transactional(value = "transactionManagerCrack", rollbackFor = Exception.class)
    public void saveChannelRetentConfig(List<ChannelRetentConfig> list) {
        if (list == null || list.size() <= 0) {
            return;
        }
        // TODO 比例如果减少了 已经执行总量也需要减少 增加了需要增加
        ChannelRetentConfig temp = list.get(0);
        String mark = temp.getMark();
        String copyMark = temp.getCopyMark();
        List<ChannelRetentConfig> configList = channelRetentConfigDAO.getConfigByMarkForPage(mark);
        Set<Integer> modifyDays = initDaySet(list);
        Set<Integer> hasDays = initDaySet(configList);
        int modifyTotal = 0;
        String key = CacheKey.AR_TASK2 + DateUtil.getDaysOfTime() + mark;
        for (Integer day : modifyDays) {
            if (!hasDays.contains(day)) {
                String execTotal = redisClient.evalHget(key, DateUtil.getPreSomeDay(day) + "exectotal");
                if (StringUtil.isNotBlank(execTotal)) {
                    modifyTotal += Integer.parseInt(execTotal);
                }
            }
        }
        for (Integer day : hasDays) {
            if (!modifyDays.contains(day)) {
                String execTotal = redisClient.evalHget(key, DateUtil.getPreSomeDay(day) + "exectotal");
                if (StringUtil.isNotBlank(execTotal)) {
                    modifyTotal -= Integer.parseInt(execTotal);
                }
            }
        }
        if (modifyTotal != 0) {
            redisClient.evalHincrby(key, "exectotal", modifyTotal);
        }
        channelRetentConfigDAO.deleteConfig(mark);
        channelRetentConfigDAO.insertConfig(list);
        if(!mark.equals(copyMark)){
            ChannelApkConfig channelApkConfig = channelApkInfoService.selectApkConfig(mark);
            ChannelApkConfig copyApkConfig = channelApkInfoService.selectApkConfig(copyMark);
            channelApkConfig.setCopyId(copyApkConfig.getId());
            List<RetentTimesConfig> timeList = new ArrayList<>();
            RetentTimesConfig retentTimesConfig = new RetentTimesConfig();
            retentTimesConfig.setMark(mark);
            retentTimesConfig.setApkId(channelApkConfig.getId());
            timeList.add(retentTimesConfig);
            retentTimesDao.delete(timeList);
            channelApkConfigDAO.copyRetentTimes(channelApkConfig);
        }

        updateWeiboRetentConfig(list);

    }

    public void updateConfig(ChannelRetentConfig config) {
        channelRetentConfigDAO.update(config);
        updateWeiboRetentConfig(config, true);
    }

    private double getExecTimesRate(int totalTimes, int times, int index, Double retentRate) {
        BigDecimal value = new BigDecimal((double) (times - index) * retentRate / totalTimes);
        return value.setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    @Transactional(value = "transactionManagerCrack", rollbackFor = Exception.class)
    private void updateWeiboRetentConfig(ChannelRetentConfig config, boolean isCheckExists) {
        String mark = config.getMark();
        if (isCheckExists) {
            WeiboBrushConfig weiboBrushConfig = new WeiboBrushConfig();
            weiboBrushConfig.setCode(mark);
            WeiboBrushConfig weiboBrushConfig1 = weiboBrushConfigDAO.selectConfig(weiboBrushConfig);
            if (weiboBrushConfig1 == null) {
                return;
            }
        }
        Integer exetimes = config.getExetimes();
        Double retentRate = config.getRetentRate();
        deleteWeiboRetentConfig(config);
        int total = 0;
        for (int i = 1; i <= exetimes; i++) {
            total += i;
        }
        for (int i = 1; i <= exetimes; i++) {
            WeiboRetentConfig weiboRetentConfig = new WeiboRetentConfig();
            weiboRetentConfig.setCode(mark);
            weiboRetentConfig.setRetentRate(getExecTimesRate(total, exetimes, i - 1, retentRate));
            weiboRetentConfig.setRetentDay(config.getRetentDay());
            weiboRetentConfig.setExecTimes(i);
            weiboRetentConfig.setPriority(config.getPriority());
            weiboRetentConfigDAO.insertConfig(weiboRetentConfig);
        }
    }

    @Transactional(value = "transactionManagerCrack", rollbackFor = Exception.class)
    private void updateWeiboRetentConfig(List<ChannelRetentConfig> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        String mark = list.get(0).getMark();
        WeiboBrushConfig weiboBrushConfig = new WeiboBrushConfig();
        weiboBrushConfig.setCode(mark);
        WeiboBrushConfig weiboBrushConfig1 = weiboBrushConfigDAO.selectConfig(weiboBrushConfig);
        if (weiboBrushConfig1 == null) {
            return;
        }
        for (ChannelRetentConfig config : list) {
            updateWeiboRetentConfig(config, false);
        }
    }

    private void deleteWeiboRetentConfig(ChannelRetentConfig config) {
        //删除微博留存配置
        WeiboRetentConfig weiboRetentConfig = new WeiboRetentConfig();
        weiboRetentConfig.setCode(config.getMark());
        weiboRetentConfig.setRetentDay(config.getRetentDay());
        weiboRetentConfigDAO.deleteConfig(weiboRetentConfig);
    }

    public void saveRetentExecTimesConfig(List<RetentTimesConfig> retentTimesConfigs) {
        retentTimesService.saveTimesConfig(retentTimesConfigs);
    }

    public void batchDeleteTimes(List<RetentTimesConfig> retentTimesConfigs) {
        retentTimesService.deleteTimesConfig(retentTimesConfigs);
    }

}
